package com.lengxf.netty.config.handler;

import com.lengxf.netty.config.ChannelContextHolder;
import com.lengxf.netty.config.NettyClientConfig;
import io.netty.channel.*;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@ChannelHandler.Sharable
public class WebsocketHandshakeHandler extends ChannelInboundHandlerAdapter {

    private final WebSocketClientHandshaker webSocketClientHandshaker = WebSocketClientHandshakerFactory.newHandshaker(
            NettyClientConfig.getServerUri(), WebSocketVersion.V13, null, false, new DefaultHttpHeaders());

    private ChannelPromise handshakeFuture;


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        handshakeFuture = ctx.newPromise();

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        webSocketClientHandshaker.handshake(channel);
        ChannelContextHolder.setChannel(channel);

    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.error("WebSocket Client disconnected and reconnect...");
        ChannelContextHolder.remove();
        super.channelInactive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (!webSocketClientHandshaker.isHandshakeComplete()) {
            doHandShake((FullHttpResponse) msg, ctx.channel());
            return;
        }
        if (msg instanceof FullHttpResponse response) {
            throw new IllegalStateException(String.format("Unexpected FullHttpResponse (getStatus= %s  , content= %s )",
                    response.status(), response.content().toString(CharsetUtil.UTF_8)));
        }
        super.channelRead(ctx, msg);
    }

    private void doHandShake(FullHttpResponse msg, Channel ch) {
        try {
            webSocketClientHandshaker.finishHandshake(ch, msg);
            log.info("WebSocket Client connected...");
            handshakeFuture.setSuccess();
        } catch (WebSocketHandshakeException e) {
            log.error("WebSocket Client failed to connect : ", e);
            handshakeFuture.setFailure(e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("exceptionCaught : ", cause);
        if (!handshakeFuture.isDone()) {
            handshakeFuture.setFailure(cause);
        }
        ctx.close();
    }

}